home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / math / ast53src.zip / XDEVICE.C < prev    next >
C/C++ Source or Header  |  1996-09-29  |  22KB  |  719 lines

  1. /*
  2. ** Astrolog (Version 5.30) File: xdevice.c
  3. **
  4. ** IMPORTANT NOTICE: The graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1996 by Walter D. Pullen
  6. ** (Astara@msn.com, http://www.magitech.com/~cruiser1/astrolog.htm).
  7. ** Permission is granted to freely use and distribute these routines
  8. ** provided one doesn't sell, restrict, or profit from them in any way.
  9. ** Modification is allowed provided these notices remain with any
  10. ** altered or edited versions of the program.
  11. **
  12. ** The main planetary calculation routines used in this program have
  13. ** been Copyrighted and the core of this program is basically a
  14. ** conversion to C of the routines created by James Neely as listed in
  15. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  16. ** available from Matrix Software. The copyright gives us permission to
  17. ** use the routines for personal use but not to sell them or profit from
  18. ** them in any way.
  19. **
  20. ** The PostScript code within the core graphics routines are programmed
  21. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  22. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  23. **
  24. ** The extended accurate ephemeris databases and formulas are from the
  25. ** calculation routines in the program "Placalc" and are programmed and
  26. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  27. ** (alois@azur.ch). The use of that source code is subject to
  28. ** regulations made by Astrodienst Zurich, and the code is not in the
  29. ** public domain. This copyright notice must not be changed or removed
  30. ** by any user of this program.
  31. **
  32. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  33. ** X Window graphics initially programmed 10/23-29/1991.
  34. ** PostScript graphics initially programmed 11/29-30/1992.
  35. ** Last code change made 9/22/1996.
  36. */
  37.  
  38. #include "astrolog.h"
  39.  
  40.  
  41. #ifdef GRAPH
  42. /*
  43. ******************************************************************************
  44. ** Bitmap File Routines.
  45. ******************************************************************************
  46. */
  47.  
  48. /* Write the bitmap array to a previously opened file in a format that   */
  49. /* can be read in by the Unix X commands bitmap and xsetroot. The 'mode' */
  50. /* parameter defines how much white space is put in the file.            */
  51.  
  52. void WriteXBitmap(file, name, mode)
  53. FILE *file;
  54. char *name, mode;
  55. {
  56.   int x, y, i, temp = 0;
  57.   _int value;
  58.  
  59.   fprintf(file, "#define %s_width %d\n" , name, gs.xWin);
  60.   fprintf(file, "#define %s_height %d\n", name, gs.yWin);
  61.   fprintf(file, "static %s %s_bits[] = {",
  62.     mode != 'V' ? "char" : "short", name);
  63.   for (y = 0; y < gs.yWin; y++) {
  64.     x = 0;
  65.     do {
  66.  
  67.       /* Process each row, eight columns at a time. */
  68.  
  69.       if (y + x > 0)
  70.         fprintf(file, ",");
  71.       if (temp == 0)
  72.         fprintf(file, "\n%s",
  73.           mode == 'N' ? "  " : (mode == 'C' ? " " : ""));
  74.       value = 0;
  75.       for (i = (mode != 'V' ? 7 : 15); i >= 0; i--)
  76.         value = (value << 1) + (!(FBmGet(gi.bm, x+i, y)^
  77.           (gs.fInverse*15))^gs.fInverse && (x + i < gs.xWin));
  78.       if (mode == 'N')
  79.         putc(' ', file);
  80.       fprintf(file, "0x");
  81.       if (mode == 'V')
  82.         fprintf(file, "%c%c",
  83.           ChHex(value >> 12), ChHex((value >> 8) & 15));
  84.       fprintf(file, "%c%c",
  85.         ChHex((value >> 4) & 15), ChHex(value & 15));
  86.       temp++;
  87.  
  88.       /* Is it time to skip to the next line while writing the file yet? */
  89.  
  90.       if ((mode == 'N' && temp >= 12) ||
  91.           (mode == 'C' && temp >= 15) ||
  92.           (mode == 'V' && temp >= 11))
  93.         temp = 0;
  94.       x += (mode != 'V' ? 8 : 16);
  95.     } while (x < gs.xWin);
  96.   }
  97.   fprintf(file, "};\n");
  98. }
  99.  
  100.  
  101. /* Write the bitmap array to a previously opened file in a simple boolean    */
  102. /* Ascii rectangle, one char per pixel, where '#' represents an off bit and  */
  103. /* '-' an on bit. The output format is identical to the format generated by  */
  104. /* the Unix bmtoa command, and it can be converted into a bitmap with atobm. */
  105.  
  106. void WriteAscii(file)
  107. FILE *file;
  108. {
  109.   int x, y, i;
  110.  
  111.   for (y = 0; y < gs.yWin; y++) {
  112.     for (x = 0; x < gs.xWin; x++) {
  113.       i = FBmGet(gi.bm, x, y);
  114.       if (gs.fColor)
  115.         putc(ChHex(i), file);
  116.       else
  117.         putc(i ? '-' : '#', file);
  118.     }
  119.     putc('\n', file);
  120.   }
  121. }
  122.  
  123.  
  124. /* Write the bitmap array to a previously opened file in the bitmap format  */
  125. /* used in Microsoft Windows for its .bmp extension files. This is a pretty */
  126. /* efficient format, only requiring a small header, and one bit per pixel   */
  127. /* for monochrome graphics, or four bits per pixel for full color.          */
  128.  
  129. void WriteBmp(file)
  130. FILE *file;
  131. {
  132.   int x, y;
  133.   dword value;
  134.  
  135.   /* Note that we sometimes only write a part of the full bitmap to disk   */
  136.   /* during the call, as done when the bitmap is being generated in bands. */
  137.  
  138.   if (gi.yBand == 0 || gi.yOffset + gi.yBand >= gs.yWin) {
  139.     /* BitmapFileHeader */
  140.     PutByte('B'); PutByte('M');
  141.     PutLong(14+40 + (gs.fColor ? 64 : 8) +
  142.       (long)4*gs.yWin*((gs.xWin-1 >> (gs.fColor ? 3 : 5))+1));
  143.     PutWord(0); PutWord(0);
  144.     PutLong(14+40 + (gs.fColor ? 64 : 8));
  145.     /* BitmapInfo / BitmapInfoHeader */
  146.     PutLong(40);
  147.     PutLong(gs.xWin); PutLong(gs.yWin);
  148.     PutWord(1); PutWord(gs.fColor ? 4 : 1);
  149.     PutLong(0 /*BI_RGB*/); PutLong(0);
  150.     PutLong(0); PutLong(0);
  151.     PutLong(0); PutLong(0);
  152.     /* RgbQuad */
  153.     if (gs.fColor)
  154.       for (x = 0; x < 16; x++) {
  155.         PutByte(RGBB(rgbbmp[x])); PutByte(RGBG(rgbbmp[x]));
  156.         PutByte(RGBR(rgbbmp[x])); PutByte(0);
  157.       }
  158.     else {
  159.       PutLong(0);
  160.       PutByte(255); PutByte(255); PutByte(255); PutByte(0);
  161.     }
  162.   }
  163.   /* Data */
  164.   for (y = (gi.yBand ? Min(gi.yBand, gs.yWin - gi.yOffset) : gs.yWin) - 1;
  165.     y >= 0; y--) {
  166.     value = 0;
  167.     for (x = 0; x < gs.xWin; x++) {
  168.       if ((x & (gs.fColor ? 7 : 31)) == 0 && x > 0) {
  169.         PutLong(value);
  170.         value = 0;
  171.       }
  172.       if (gs.fColor)
  173.         value |= (dword)FBmGet(gi.bm, x, y) << ((x & 7 ^ 1) << 2);
  174.       else
  175.         if (FBmGet(gi.bm, x, y))
  176.           value |= (dword)1 << (x & 31 ^ 7);
  177.     }
  178.     PutLong(value);
  179.   }
  180. }
  181.  
  182.  
  183. /* Begin the work of creating a graphics file. Prompt for a filename if */
  184. /* need be, and if valid, create the file and open it for writing.      */
  185.  
  186. void BeginFileX()
  187. {
  188.   char line[cchSzDef];
  189.  
  190.   if (us.fNoWrite)
  191.     return;
  192. #ifndef WIN
  193.   if (gi.szFileOut == NULL && (
  194. #ifdef PS
  195.     gi.fEps ||
  196. #endif
  197.     gs.fMeta || (gs.fBitmap && gs.chBmpMode == 'B'))) {
  198.     sprintf(line, "(It is recommended to specify an extension of '.%s'.)\n",
  199.       gs.fBitmap ? "bmp" :
  200. #ifdef PS
  201.       (gi.fEps ? "eps" : "wmf")
  202. #else
  203.       "wmf"
  204. #endif
  205.       );
  206.     PrintSzScreen(line);
  207.   }
  208. #endif /* WIN */
  209.   loop {
  210.     if (gi.szFileOut == NULL) {
  211.       sprintf(line, "Enter name of file to write %s to",
  212.         gs.fBitmap ? "bitmap" : (gs.fPS ? "PostScript" : "metafile"));
  213.       InputString(line, line);
  214.       gi.szFileOut = line;
  215.     }
  216.     gi.file = fopen(gi.szFileOut, gs.fPS ? "w" : "wb");
  217.     if (gi.file != NULL)
  218.       break;
  219.     else {
  220.       PrintWarning("Couldn't create output file.");
  221.       gi.szFileOut = NULL;
  222.     }
  223.   }
  224. }
  225.  
  226.  
  227. /* Finish up the work of creating a graphics file. This basically consists */
  228. /* of just calling the appropriate routine to actually write the data in   */
  229. /* memory to a file for bitmaps and metafiles, although for PostScript we  */
  230. /* just close file as we were already writing while creating the chart.    */
  231.  
  232. void EndFileX()
  233. {
  234.   char sz[cchSzDef];
  235.  
  236.   if (gs.fBitmap) {
  237.     if (gi.yBand) {
  238.       sprintf(sz, "Writing part %d of chart bitmap to file.",
  239.         gi.yOffset / gi.yBand + 1);
  240.       PrintNotice(sz);
  241.     } else
  242.       PrintNotice("Writing chart bitmap to file.");
  243.     if (gs.chBmpMode == 'B')
  244.       WriteBmp(gi.file);
  245.     else if (gs.chBmpMode == 'A')
  246.       WriteAscii(gi.file);
  247.     else
  248.       WriteXBitmap(gi.file, gi.szFileOut, gs.chBmpMode);
  249.   }
  250. #ifdef PS
  251.   else if (gs.fPS)
  252.     PsEnd();
  253. #endif
  254. #ifdef META
  255.   else {
  256.     PrintNotice("Writing metafile to disk.");
  257.     WriteMeta(gi.file);
  258.   }
  259. #endif
  260.   if (!gs.fBitmap || gi.yOffset == 0) {
  261.     fclose(gi.file);
  262.     gi.yBand = 0;
  263.   }
  264. #ifdef WIN
  265.   if (wi.wCmd == cmdSaveWallTile || wi.wCmd == cmdSaveWallCenter) {
  266.     WriteProfileString("Desktop", "TileWallpaper",
  267.       wi.wCmd == cmdSaveWallTile ? "1" : "0");
  268.     SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, gi.szFileOut,
  269.       SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
  270.     wi.wCmd = 0;
  271.   }
  272. #endif
  273. }
  274.  
  275.  
  276. #ifdef PS
  277. /*
  278. ******************************************************************************
  279. ** PostScript File Routines.
  280. ******************************************************************************
  281. */
  282.  
  283. /* Table of PostScript header alias lines used by the program. */
  284.  
  285. CONST char FPTR szPsFunctions[] =
  286. "/languagelevel where{pop languagelevel}{1}ifelse\
  287.  2 lt{\n\
  288. /sf{exch findfont exch\
  289.  dup type/arraytype eq{makefont}{scalefont}ifelse setfont}bind def\n\
  290. /rf{gsave newpath\n\
  291. 4 -2 roll moveto\
  292.  dup 0 exch rlineto exch 0 rlineto neg 0 exch rlineto closepath\n\
  293. fill grestore}bind def\n\
  294. /rc{newpath\n\
  295. 4 -2 roll moveto\
  296.  dup 0 exch rlineto exch 0 rlineto neg 0 exch rlineto closepath\n\
  297. clip newpath}bind def\n\
  298. }{/sf/selectfont load def/rf/rectfill load def\
  299. /rc/rectclip load def}ifelse\n\
  300. /center{0 begin gsave dup 4 2 roll\
  301.  translate newpath 0 0 moveto\
  302.  false charpath flattenpath pathbbox\
  303.  /URy exch def/URx exch def/LLy exch def/LLx exch def\
  304.  URx LLx sub 0.5 mul LLx add neg URy LLy sub 0.5 mul LLy add neg\
  305.  0 0 moveto rmoveto\
  306.  show grestore end}bind def\n\
  307. /center load 0 4 dict put\n\
  308. /c{setrgbcolor}bind def\n\
  309. /d{moveto 0 0 rlineto}bind def\n\
  310. /l{4 2 roll moveto lineto}bind def\n\
  311. /t{lineto}bind def\n\
  312. /el{newpath matrix currentmatrix 5 1 roll translate scale\
  313.  0 0 1 0 360 arc setmatrix stroke}bind def\n";
  314.  
  315.  
  316. /* Write a command to flush the PostScript buffer. */
  317.  
  318. void PsStrokeForce()
  319. {
  320.   if (gi.cStroke > 0) {              /* render any existing path */
  321.     fprintf(gi.file, "stroke\n");
  322.     gi.cStroke = 0;
  323.     gi.xPen = -1;                    /* Invalidate PolyLine cache */
  324.   }
  325. }
  326.  
  327.  
  328. /* Indicate that a certain number of PostScript commands have been done. */
  329.  
  330. void PsStroke(n)
  331. int n;
  332. {
  333.   gi.cStroke += n;
  334.   if (gi.cStroke > 2000)    /* Whenever we reach a certain limit, flush. */
  335.     PsStrokeForce();
  336. }
  337.  
  338.  
  339. /* Set the type of line end to be used by PostScript commands. If linecap */
  340. /* is true, then the line ends are rounded, otherwise they are squared.   */
  341.  
  342. void PsLineCap(fLineCap)
  343. bool fLineCap;
  344. {
  345.   if (fLineCap != gi.fLineCap) {
  346.     PsStrokeForce();
  347.     fprintf(gi.file, "%d setlinecap\n", fLineCap);
  348.     gi.fLineCap = fLineCap;
  349.   }
  350. }
  351.  
  352.  
  353. /* Set the dash length to be used by PostScript line commands. */
  354.  
  355. void PsDash(dashoff)
  356. int dashoff;
  357. {
  358.   if (dashoff != gi.nDash) {
  359.     PsStrokeForce();
  360.     if (dashoff)
  361.       fprintf(gi.file, "[%d %d", PSMUL, dashoff * PSMUL);
  362.     else
  363.       fprintf(gi.file, "[");
  364.     fprintf(gi.file, "]0 setdash\n");
  365.     gi.nDash = dashoff;
  366.   }
  367. }
  368.  
  369.  
  370. /* Set a linewidth size to be used by PostScript figure primitive commands. */
  371.  
  372. void PsLineWidth(linewidth)
  373. int linewidth;
  374. {
  375.   if ((real)linewidth != gi.rLineWid) {
  376.     PsStrokeForce();
  377.     fprintf(gi.file, "%d setlinewidth\n", linewidth);
  378.     gi.rLineWid = (real)linewidth;
  379.   }
  380. }
  381.  
  382.  
  383. /* Set a system font and size to be used by PostScript text commands. */
  384.  
  385. void PsFont(psfont)
  386. int psfont;
  387. {
  388.   int z;
  389.  
  390.   if (psfont != gi.nFont && gs.fFont) {
  391.     if (psfont <= 2) {
  392.       z = psfont == 1 ? 32*PSMUL : 23*PSMUL;
  393.       fprintf(gi.file, "/Astro[%d 0 0 -%d 0 0]sf\n", z, z);
  394.     } else if (psfont == 3) {
  395.       z = 26*PSMUL;
  396.       fprintf(gi.file, "/Times-Roman[%d 0 0 -%d 0 0]sf\n", z, z);
  397.     } else {
  398.       z = 10*PSMUL;
  399.       fprintf(gi.file, "/Courier[%d 0 0 -%d 0 0]sf\n", z, z);
  400.     }
  401.     gi.nFont = psfont;
  402.   }
  403. }
  404.  
  405.  
  406. /* Prompt the user for the name of a file to write the PostScript file to */
  407. /* (if not already specified), open it, and write out file header info.   */
  408.  
  409. void PsBegin()
  410. {
  411.   fprintf(gi.file, "%%!PS-Adobe-2.0");
  412.   if (gi.fEps)
  413.     fprintf(gi.file, " EPSF-2.0");
  414.   fprintf(gi.file, "\n%%%%Title: %s\n", gi.szFileOut);
  415.   fprintf(gi.file, "%%%%Creator: %s %s\n", szAppName, szVersionCore);
  416.   fprintf(gi.file, "%%%%CreationDate: %s\n", szDateCore);
  417.   if (gi.fEps) {
  418.     fprintf(gi.file, "%%%%BoundingBox: 0 0 %d %d\n", gs.xWin, gs.yWin);
  419.     fprintf(gi.file, "%%%%EndComments\n");
  420.     fprintf(gi.file, "%%%%BeginSetup\n");
  421.     fprintf(gi.file, szPsFunctions, 6 * PSMUL, 6 * PSMUL);
  422.     fprintf(gi.file, "%%%%EndSetup\n");
  423.     fprintf(gi.file, "0 0 %d %d rc\n", gs.xWin, gs.yWin);
  424.   } else {
  425.     fprintf(gi.file, "%%%%Pages: 1 1\n");
  426.     fprintf(gi.file, "%%%%DocumentFonts: (atend)\n");
  427.     fprintf(gi.file, "%%%%BoundingBox: %d %d %d %d\n", PSGUTTER, PSGUTTER,
  428.       (int)(gs.xInch*72.0+rRound)-PSGUTTER,
  429.       (int)(gs.yInch*72.0+rRound)-PSGUTTER);
  430.     fprintf(gi.file, "%%%%EndComments\n");
  431.     fprintf(gi.file, "%%%%BeginProcSet: common\n");
  432.     fprintf(gi.file, szPsFunctions, 6 * PSMUL, 6 * PSMUL);
  433.     fprintf(gi.file, "%%%%EndProcSet\n");
  434.     fprintf(gi.file, "%%%%Page: 1 1\n");
  435.   }
  436.   PsFont(2);
  437.   fprintf(gi.file, "gsave\n");
  438.   PsLineWidth(gi.nPenWid/2);
  439.   gi.xPen = -1;
  440.   PrintNotice("Creating PostScript chart file.");
  441. }
  442.  
  443.  
  444. /* Write out trailing information to the PostScript file and close it. */
  445.  
  446. void PsEnd()
  447. {
  448.   PsStrokeForce();
  449.   if (gi.fEps)
  450.     fprintf(gi.file, "%%%%EOF\n");
  451.   else {
  452.     fprintf(gi.file, "showpage\n");
  453.     fprintf(gi.file, "%%%%PageTrailer\n");
  454.     fprintf(gi.file, "%%%%Trailer\n");
  455.     fprintf(gi.file, "%%%%DocumentFonts: Times-Roman\n");
  456.     if (gs.fFont) {
  457.       fprintf(gi.file, "%%%%+ Courier\n");
  458.       fprintf(gi.file, "%%%%+ Astro\n");
  459.     }
  460.   }
  461.   fclose(gi.file);
  462. }
  463. #endif /* PS */
  464.  
  465.  
  466. #ifdef META
  467. /*
  468. ******************************************************************************
  469. ** Metafile Routines.
  470. ******************************************************************************
  471. */
  472.  
  473. /* Output one 16 bit or 32 bit value into the metafile buffer stream. */
  474.  
  475. void MetaWord(w)
  476. word w;
  477. {
  478.   char sz[cchSzDef];
  479.  
  480.   if ((hpbyte)gi.pwMetaCur - gi.bm >= gi.cbMeta) {
  481.     sprintf(sz, "Metafile would be more than %ld bytes.", gi.cbMeta);
  482.     PrintError(sz);
  483.     Terminate(tcFatal);
  484.   }
  485.   *gi.pwMetaCur = w;
  486.   gi.pwMetaCur++;
  487. }
  488.  
  489. void MetaLong(l)
  490. long l;
  491. {
  492.   MetaWord(WLo(l));
  493.   MetaWord(WHi(l));
  494. }
  495.  
  496.  
  497. /* Output any necessary metafile records to make the current actual     */
  498. /* settings of line color, fill color, etc, be those that we know are   */
  499. /* desired. This is generally called by the primitives routines before  */
  500. /* any figure record is actually written into a metafile. We wait until */
  501. /* the last moment before changing any settings to ensure that we don't */
  502. /* output any unnecessary records, e.g. two select colors in a row.     */
  503.  
  504. void MetaSelect()
  505. {
  506.   if (gi.kiLineDes != gi.kiLineAct) {
  507.     MetaSelectObject(gi.kiLineDes);
  508.     gi.kiLineAct = gi.kiLineDes;
  509.   }
  510.   if (gi.kiFillDes != gi.kiFillAct) {
  511.     MetaSelectObject(16*4 + gi.kiFillDes);
  512.     gi.kiFillAct = gi.kiFillDes;
  513.   }
  514.   if (gi.nFontDes != gi.nFontAct) {
  515.     MetaSelectObject(16*5 + gi.nFontDes);
  516.     gi.nFontAct = gi.nFontDes;
  517.   }
  518.   if (gi.kiTextDes != gi.kiTextAct) {
  519.     MetaTextColor(rgbbmp[gi.kiTextDes]);
  520.     gi.kiTextAct = gi.kiTextDes;
  521.   }
  522.   if (gi.nAlignDes != gi.nAlignAct) {
  523.     MetaTextAlign(gi.nAlignDes);
  524.     gi.nAlignAct = gi.nAlignDes;
  525.   }
  526.   gi.xPen = -1;    /* Invalidate PolyLine cache */
  527. }
  528.  
  529.  
  530. /* Output initial metafile header information into our metafile buffer. */
  531. /* We also setup and create all pen, brush, and font objects that may   */
  532. /* possibly be used in the generation and playing of the picture.       */
  533.  
  534. void MetaInit()
  535. {
  536.   int i, j, k;
  537.  
  538.   gi.pwMetaCur = (word HPTR *)gi.bm;
  539.   /* Placable Metaheader */
  540.   MetaLong(0x9AC6CDD7L);
  541.   MetaWord(0);      /* Not used */
  542.   MetaWord(0); MetaWord(0);
  543.   MetaWord(gs.xWin); MetaWord(gs.yWin);
  544.   MetaWord(gs.xWin/6);                     /* Units per inch */
  545.   MetaLong(0L);     /* Not used */
  546.   MetaWord(0x9AC6 ^ 0xCDD7 ^ gs.xWin ^ gs.yWin ^ gs.xWin/6);  /* Checksum */
  547.   /* Metaheader */
  548.   MetaWord(1);                      /* Metafile type                    */
  549.   MetaWord(9);                      /* Size of header in words          */
  550.   MetaWord(0x300);                  /* Windows version                  */
  551.   MetaLong(0L);                     /* Size of entire metafile in words */
  552.   MetaWord(16*5+1+(gs.fFont>0)*4);  /* Number of objects in metafile    */
  553.   MetaLong(17L);                    /* Size of largest record in words  */
  554.   MetaWord(0);                      /* Not used                         */
  555.   /* Setup */
  556.   MetaEscape(17);
  557.   MetaLong(LFromBB('A', 's', 't', 'r'));  /* "Astr" */
  558.   MetaWord(4);                            /* Creator */
  559.   MetaLong(14L);                          /* Bytes in string */
  560.   MetaLong(LFromBB('A', 's', 't', 'r'));  /* "Astr" */
  561.   MetaLong(LFromBB('o', 'l', 'o', 'g'));  /* "olog" */
  562.   MetaLong(LFromBB(' ', '5', '.', '3'));  /* " 5.3" */
  563.   MetaWord(WFromBB('0', 0));              /* "0"    */
  564.   MetaSaveDc();
  565.   MetaWindowOrg(0, 0);
  566.   MetaWindowExt(gs.xWin, gs.yWin);
  567.   MetaBkMode(1 /* Transparent */);
  568.   /* Colors */
  569.   for (j = 1; j <= 4; j++)
  570.     for (i = 0; i < 16; i++) {
  571.       k = j <= 1 ? gi.nPenWid : 0;
  572.       MetaCreatePen(j <= 2 ? 0 : j-2 /* PS_SOLID; PS_DASH; PS_DOT */,
  573.         k, rgbbmp[i]);
  574.     }
  575.   for (i = 0; i < 16; i++) {
  576.     MetaCreateBrush(0 /* BS_SOLID */, rgbbmp[i]);
  577.   }
  578.   MetaCreateBrush(1 /* BS_NULL */, 0L);
  579.   /* Fonts */
  580.   if (gs.fFont) {
  581.     MetaCreateFont(5, 0, -8*gi.nScale, 2 /* Symbol Charset */);
  582.     MetaWord(WFromBB(1 /* Draft */, 1 | 0x10 /* Fixed | Roman */));
  583.     MetaLong(LFromBB('W', 'i', 'n', 'g'));
  584.     MetaLong(LFromBB('d', 'i', 'n', 'g'));
  585.     MetaWord(WFromBB('s', 0));
  586.  
  587.     MetaCreateFont(8, 0, -6*gi.nScale, 0 /* Ansi Charset */);
  588.     MetaWord(WFromBB(0 /* Default */, 2 | 0x10 /* Variable | Roman */));
  589.     MetaLong(LFromBB('T', 'i', 'm', 'e'));
  590.     MetaLong(LFromBB('s', ' ', 'N', 'e'));
  591.     MetaLong(LFromBB('w', ' ', 'R', 'o'));
  592.     MetaLong(LFromBB('m', 'a', 'n', 0));
  593.  
  594.     MetaCreateFont(6, 6*METAMUL, 10*METAMUL, 0 /* Ansi Charset */);
  595.     MetaWord(WFromBB(1 /* Draft */, 1 | 0x30 /* Fixed | Modern */));
  596.     MetaLong(LFromBB('C', 'o', 'u', 'r'));
  597.     MetaLong(LFromBB('i', 'e', 'r', ' '));
  598.     MetaLong(LFromBB('N', 'e', 'w', 0));
  599.  
  600.     MetaCreateFont(8, 0, -11*gi.nScale, 0 /* Ansi Charset */);
  601.     MetaWord(WFromBB(0 /* Default */, 2 | 0 /* Variable | Don't Care */));
  602.     MetaLong(LFromBB('A', 's', 't', 'r'));
  603.     MetaLong(LFromBB('o', '-', 'S', 'e'));
  604.     MetaLong(LFromBB('m', 'i', 'B', 'o'));
  605.     MetaLong(LFromBB('l', 'd', 0, 0));
  606.   }
  607. }
  608.  
  609.  
  610. /* Output trailing records to indicate the end of the metafile and then */
  611. /* actually write out the entire buffer to the specifed file.           */
  612.  
  613. void WriteMeta(file)
  614. FILE *file;
  615. {
  616.   word HPTR *w;
  617. #if FALSE
  618.   int i;
  619.  
  620.   for (i = 16*5+1+(gs.fFont>0)*4; i >= 0; i--) {
  621.     MetaDeleteObject(i);
  622.   }
  623. #endif
  624.   MetaRestoreDc();
  625.   MetaRecord(3, 0);    /* End record */
  626.   *(long HPTR *)(gi.bm + 22 + 6) =
  627.     ((long)((hpbyte)gi.pwMetaCur - gi.bm) - 22) / 2;
  628.   for (w = (word HPTR *)gi.bm; w < gi.pwMetaCur; w++) {
  629.     PutWord(*w);
  630.   }
  631. }
  632. #endif /* META */
  633.  
  634.  
  635. #ifdef MOUSE
  636. #ifdef PC
  637. /*
  638. ******************************************************************************
  639. ** Mouse Routines.
  640. ******************************************************************************
  641. */
  642.  
  643. static union REGS dosreg;
  644.  
  645.  
  646. /* Setup and initialize the PC graphics mouse, returning the number of    */
  647. /* buttons available, or zero for no mouse at all. Passed in is the pixel */
  648. /* size of the screen the mouse pointer is to be contained within.        */
  649.  
  650. int MouseInit(x, y)
  651. int x, y;
  652. {
  653.   int dx, cBtn;
  654.  
  655.   if (!gs.fMouse)
  656.     return 0;
  657.   dosreg.x.ax = 0;
  658.   int86(0x33, &dosreg, &dosreg);
  659.   if (!(gs.fMouse = dosreg.x.ax))
  660.     return 0;
  661.   cBtn = dosreg.x.bx;
  662.   dx = x - 1;
  663.   dosreg.x.ax = 7;
  664.   dosreg.x.cx = 0;
  665.   dosreg.x.dx = dx;
  666.   int86(0x33, &dosreg, &dosreg);
  667.   dx = y - 1;
  668.   dosreg.x.ax = 8;
  669.   dosreg.x.cx = 0;
  670.   dosreg.x.dx = dx;
  671.   int86(0x33, &dosreg, &dosreg);
  672.   return cBtn;
  673. }
  674.  
  675.  
  676. /* Turn on or hide the PC graphics mouse pointer. */
  677.  
  678. void MouseShow(fShow)
  679. bool fShow;
  680. {
  681.   int ax;
  682.  
  683.   if (!gs.fMouse)
  684.     return;
  685.   ax = fShow ? 1 : 2;
  686.   dosreg.x.ax = ax;
  687.   int86(0x33, &dosreg, &dosreg);
  688. }
  689.  
  690.  
  691. /* Fill out the current status of the mouse: its horizontal and vertical  */
  692. /* position, and button press status. We return false if the mouse hasn't */
  693. /* changed any from the last call (assuming that the previous values are  */
  694. /* stored in the input parameters) or if the mouse isn't active at all.   */
  695.  
  696. bool MouseStatus(x, y, btn)
  697. int *x, *y, *btn;
  698. {
  699.   int bx, cx, dx, fChange;
  700.  
  701.   if (!gs.fMouse)
  702.     return fFalse;
  703.   dosreg.x.ax = 3;
  704.   int86(0x33, &dosreg, &dosreg);
  705.   bx = dosreg.x.bx;
  706.   cx = dosreg.x.cx;
  707.   dx = dosreg.x.dx;
  708.   fChange = (cx != *x || dx != *y || bx != *btn);
  709.   *x = cx;
  710.   *y = dx;
  711.   *btn = bx;
  712.   return fChange;
  713. }
  714. #endif /* PC */
  715. #endif /* MOUSE */
  716. #endif /* GRAPH */
  717.  
  718. /* xdevice.c */
  719.